/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.beans.beaninfo; import java.lang.reflect.Modifier; import java.util.List; import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; import java.util.StringTokenizer; import java.util.ResourceBundle; import org.openide.src.MethodElement; import org.openide.src.ClassElement; import org.openide.src.Type; import org.openide.nodes.Node; import org.openide.TopManager; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; import org.netbeans.modules.beans.PatternAnalyser; import org.netbeans.modules.beans.Pattern; import org.netbeans.modules.beans.PropertyPattern; import org.netbeans.modules.beans.IdxPropertyPattern; import org.netbeans.modules.beans.EventSetPattern; /** Analyses the ClassElement trying to find source code patterns i.e. * properties or event sets; * * @author Petr Hrebejk */ public class BiAnalyser extends Object implements Node.Cookie { private static final ResourceBundle bundle = NbBundle.getBundle( BiAnalyser.class ); private static final String TAB = " "; // NOI18N private static final String TABx2 = TAB +TAB; private static final String TABx3 = TAB + TABx2; private static final String ICONNAME_C16 = "iconNameC16"; // NOI18N private static final String ICONNAME_C32 = "iconNameC32"; // NOI18N private static final String ICONNAME_M16 = "iconNameM16"; // NOI18N private static final String ICONNAME_M32 = "iconNameM32"; // NOI18N private static final String DEFAULT_PROPERTY_INDEX = "defaultPropertyIndex"; // NOI18N private static final String DEFAULT_EVENT_INDEX = "defaultEventIndex"; // NOI18N /** Holds all properties * @associates Property*/ List properties; /** Holds all indexed properties * @associates IdxProperty*/ List idxProperties; /** Holds all events sets * @associates EventSet*/ List eventSets; /** Holds all methods */ List methods; /** Object representing source code of associated BeanInfo */ BeanInfoSource bis; /** Should properties be obtained from introspection */ private boolean nullProperties = false; /** Should event sets be obtained from introspection */ private boolean nullEventSets = false; /* Holds the class for which the bean info is generated */ ClassElement classElement; private String iconC16; private String iconM16; private String iconC32; private String iconM32; private int defaultPropertyIndex = -1; private int defaultEventIndex = -1; /** Creates Bean Info analyser which contains all patterns from PatternAnalyser */ BiAnalyser ( PatternAnalyser pa, ClassElement classElement ) { Collection col; Iterator it; this.classElement = classElement; // Fill properties list col = pa.getPropertyPatterns(); properties = new ArrayList( col.size() ); it = col.iterator(); while( it.hasNext() ) { PropertyPattern pp = (PropertyPattern)it.next(); //if ( pp.isPublic() ) properties.add( new BiFeature.Property( pp ) ); } // Fill indexed properties list col = pa.getIdxPropertyPatterns(); idxProperties = new ArrayList( col.size() ); it = col.iterator(); while( it.hasNext() ) { IdxPropertyPattern ipp = (IdxPropertyPattern)it.next(); //if ( ipp.isPublic() ) if ( ipp.getType() != null && ( !ipp.getType().isArray() || !ipp.getType().getElementType().equals( ipp.getIndexedType() ) ) ) { continue; } idxProperties.add( new BiFeature.IdxProperty( ipp ) ); } // Fill event sets list col = pa.getEventSetPatterns(); eventSets = new ArrayList( col.size() ); it = col.iterator(); while( it.hasNext() ) { EventSetPattern esp = (EventSetPattern)it.next(); //if ( esp.isPublic() ) eventSets.add( new BiFeature.EventSet( esp ) ); } // Try to find and analyse existing bean info bis = new BeanInfoSource( classElement ); analyzeBeanInfoSource( ); } Collection getProperties() { return properties; } Collection getIdxProperties() { return idxProperties; } Collection getEventSets() { return eventSets; } Collection getMethods() { return methods; } public String getIconC16() { return iconC16; } public void setIconC16(String iconC16) { this.iconC16 = iconC16; } public String getIconM16() { return iconM16; } public void setIconM16(String iconM16) { this.iconM16 = iconM16; } public String getIconC32() { return iconC32; } public void setIconC32(String iconC32) { this.iconC32 = iconC32; } public String getIconM32() { return iconM32; } public void setIconM32(String iconM32) { this.iconM32 = iconM32; } public int getDefaultPropertyIndex() { return defaultPropertyIndex; } public void setDefaultPropertyIndex(int defaultPropertyIndex) { this.defaultPropertyIndex = defaultPropertyIndex; } public int getDefaultEventIndex() { return defaultEventIndex; } public void setDefaultEventIndex(int defaultEventIndex) { this.defaultEventIndex = defaultEventIndex; } boolean isNullProperties() { return nullProperties; } void setNullProperties( boolean nullProperties ) { this.nullProperties = nullProperties; } boolean isNullEventSets() { return nullEventSets; } void setNullEventSets( boolean nullEventSets ) { this.nullEventSets = nullEventSets; } void regenerateSource() { if ( bis.exists() ) { if ( !bis.isNbBeanInfo() ) { String mssg = NbBundle.getBundle(BiAnalyser.class).getString( "MSG_BeanInfoExists" ); NotifyDescriptor nd = new NotifyDescriptor.Confirmation ( mssg, NotifyDescriptor.YES_NO_OPTION ); TopManager.getDefault().notify( nd ); if ( !nd.getValue().equals ( NotifyDescriptor.YES_OPTION ) ) { return; } try { bis.delete(); } catch ( java.io.IOException e ) { mssg = NbBundle.getBundle(BiAnalyser.class).getString( "MSG_BeanInfoCantDelete" ); nd = new NotifyDescriptor.Message ( mssg ); TopManager.getDefault().notify( nd ); return; } bis.createFromTemplate(); } } else { bis.createFromTemplate(); if ( !bis.isNbBeanInfo() ) { return; } } javax.swing.SwingUtilities.invokeLater( new Runnable() { public void run() { bis.open(); regenerateProperties(); regenerateEvents(); regenerateIcons(); regenerateDefaultIdx(); } } ); } /** Regenerates the property section of BeanInfo */ private void regenerateProperties() { StringBuffer sb = new StringBuffer( 512 ); int propertyCount = 0; if ( nullProperties ) { sb.append( TAB + bundle.getString( "COMMENT_NullProperties" ) ); sb.append( TAB + "private static PropertyDescriptor[] properties = null;\n" ); // NOI18N bis.setPropertiesSection( sb.toString(), " \n" ); // NOI18N return; } // Make common list of all properites ArrayList allProperties = new ArrayList( getProperties().size() + getIdxProperties().size() ); allProperties.addAll( getProperties() ); allProperties.addAll( getIdxProperties() ); sb.append( TAB + bundle.getString( "COMMENT_PropertyIdentifiers" ) ); Iterator it = allProperties.iterator(); while ( it.hasNext() ) { BiFeature bif = ( BiFeature )it.next(); if ( bif.isIncluded() ) { sb.append( TAB + "private static final int " ); // NOI18N sb.append( "PROPERTY_" + bif.getName() ); // NOI18N sb.append( " = " + (propertyCount++) + ";" ); // NOI18N sb.append( "\n" ); // NOI18N } } sb.append( "\n" + TAB + bundle.getString("COMMENT_PropertyArray" )); sb.append( TAB + "private static PropertyDescriptor[] properties = new PropertyDescriptor[" + // NOI18N propertyCount + "];\n\n" ); // NOI18N if ( propertyCount > 0) sb.append( TAB + "static {\n" + TABx2 + "try {\n" ); // NOI18N it = allProperties.iterator(); for ( int i = 0; it.hasNext(); i++ ) { BiFeature bif = ( BiFeature )it.next(); if ( bif.isIncluded() ) { sb.append( TABx3 + "properties[PROPERTY_" ).append( bif.getName() ).append("] = "); // NOI18N sb.append( bif.getCreationString() ).append(";\n"); // NOI18N Collection cs = bif.getCustomizationStrings(); Iterator csit = cs.iterator(); while( csit.hasNext() ) { sb.append( TABx3 + "properties[PROPERTY_" ).append( bif.getName() ).append("]."); // NOI18N sb.append( (String)csit.next() ).append( ";\n" ); // NOI18N } } } if ( propertyCount > 0 ) sb.append( TABx2 + "}\n" + TABx2 + "catch( IntrospectionException e) {}" ); // NOI18N bis.setPropertiesSection( sb.toString(), propertyCount > 0 ? "}\n" : " \n" ); // NOI18N } /** Regenerates the event set section of BeanInfo */ private void regenerateEvents() { StringBuffer sb = new StringBuffer( 512 ); int eventCount = 0; if ( nullEventSets ) { sb.append( TAB + bundle.getString( "COMMENT_NullEventSets" ) ); sb.append( TAB + "private static EventSetDescriptor[] eventSets = null;\n" ); // NOI18N bis.setEventSetsSection( sb.toString(), " \n" ); // NOI18N return; } sb.append( TAB + bundle.getString("COMMENT_EventSetsIdentifiers") ); Iterator it = eventSets.iterator(); while ( it.hasNext() ) { BiFeature bif = ( BiFeature )it.next(); if ( bif.isIncluded() ) { sb.append( TAB + "private static final int " ); // NOI18N sb.append( "EVENT_" + bif.getName() ); // NOI18N sb.append( " = " + (eventCount++) + ";" ); // NOI18N sb.append( "\n" ); // NOI18N } } sb.append( "\n" + TAB + bundle.getString("COMMENT_EventSetsArray")); sb.append( TAB + "private static EventSetDescriptor[] eventSets = new EventSetDescriptor[" // NOI18N + eventCount + "];\n\n" ); // NOI18N if ( eventCount > 0 ) sb.append( TAB + "static {\n" + TABx2 + "try {\n" ); // NOI18N it = eventSets.iterator(); for ( int i = 0; it.hasNext(); i++ ) { BiFeature bif = ( BiFeature )it.next(); if ( bif.isIncluded() ) { sb.append( TABx3 + "eventSets[EVENT_" ).append( bif.getName() ).append("] = "); // NOI18N sb.append( bif.getCreationString() ).append(";\n"); // NOI18N Collection cs = bif.getCustomizationStrings(); Iterator csit = cs.iterator(); while( csit.hasNext() ) { sb.append( TABx3 + "eventSets[EVENT_" ).append( bif.getName() ).append("]."); // NOI18N sb.append( (String)csit.next() ).append( ";\n" ); // NOI18N } } } if ( eventCount > 0 ) sb.append( TABx2 + "}\n" + TABx2 + "catch( IntrospectionException e) {}" ); // NOI18N bis.setEventSetsSection( sb.toString(), eventCount > 0 ? "}\n" : " \n"); // NOI18N } /** Generate image icon section */ private void regenerateIcons() { StringBuffer sb = new StringBuffer( 200 ); sb.append( getIconDeclaration( ICONNAME_C16, iconC16 )); sb.append( getIconDeclaration( ICONNAME_C32, iconC32 )); sb.append( getIconDeclaration( ICONNAME_M16, iconM16 )); sb.append( getIconDeclaration( ICONNAME_M32, iconM32 )); bis.setIconsSection( sb.toString() ); } private static String getIconDeclaration( String name, String resource ) { StringBuffer sb = new StringBuffer( 80 ); sb.append( TAB + "private static String " ).append( name ).append( " = "); // NOI18N if ( resource == null || resource.trim().length() == 0 ) sb.append( "null;\n"); // NOI18N else sb.append("\"").append( resource.trim() ).append("\";\n"); // NOI18N return sb.toString(); } private void regenerateDefaultIdx() { StringBuffer sb = new StringBuffer(100); sb.append( TAB + "private static int " + DEFAULT_PROPERTY_INDEX + " = ").append( defaultPropertyIndex ).append( ";\n"); // NOI18N sb.append( TAB + "private static int " + DEFAULT_EVENT_INDEX + " = ").append( defaultEventIndex ).append( ";\n"); // NOI18N bis.setDefaultIdxSection( sb.toString() ); } /** Analyzes existing BeanInfo */ private void analyzeBeanInfoSource() { if ( !bis.isNbBeanInfo() ) return; String section = bis.getIconsSection(); Collection code = normalizeText( section ); setIconsFromBeanInfo( code ); section = bis.getDefaultIdxSection(); code = normalizeText( section ); setDefaultIdxFromBeanInfo( code ); section = bis.getPropertiesSection(); code = normalizeText( section ); nullProperties = setPropertiesFromBeanInfo( properties, code, "PropertyDescriptor[]" ); // NOI18N if ( !nullProperties ) setPropertiesFromBeanInfo( idxProperties, code, "PropertyDescriptor[]" ); // NOI18N section = bis.getEventSetsSection(); code = normalizeText( section ); nullEventSets = setPropertiesFromBeanInfo( eventSets, code, "EventSetDescriptor[]" ); // NOI18N } /** "Normalizes" the JavaCode. Removes all unneeded whitespaces. Makes strings from * commands. * @param code String containg the java source code * @returns Normalized code as collection of string. */ static Collection normalizeText( String code ) { ArrayList result = new ArrayList(); StringBuffer sb = new StringBuffer( 100 ); final int IN_TEXT = 0; final int IN_WHITE = 1; int mode = IN_WHITE; boolean eo_javaid = false; for ( int i = 0; i < code.length(); i++ ) { char ch = code.charAt( i ); switch ( mode ) { case IN_TEXT: if ( !Character.isWhitespace( ch ) ) { if ( ch == ';' ) { sb.append( ch ); result.add( sb.toString() ); sb.setLength( 0 ); mode = IN_WHITE; eo_javaid = false; } else sb.append( ch ); } else { eo_javaid = Character.isJavaIdentifierPart ( code.charAt( i - 1 ) ); mode = IN_WHITE; } break; case IN_WHITE: if ( !Character.isWhitespace( ch ) ) { if ( eo_javaid && Character.isJavaIdentifierStart ( ch ) ) sb.append( ' ' ); sb.append( ch ); mode = IN_TEXT; } break; } } return result; } static String[] getParameters( String command ) { //ArrayList result = new ArrayList(); String paramString; int beg = command.lastIndexOf( '(' ); int end = command.lastIndexOf( ')' ); if ( beg != -1 && end != -1 && ( ++beg < end ) ) paramString = command.substring( beg, end ); else return new String[0]; StringTokenizer strTok = new StringTokenizer( paramString, ",)" ); // NOI18N String[] resultStrs = new String[ strTok.countTokens() ]; for ( int i = 0; strTok.hasMoreTokens(); i++ ) resultStrs[i] = strTok.nextToken(); return resultStrs; } /** Gets the initializer */ static String getInitializer( String command ) { int beg = command.lastIndexOf( '=' ); int end = command.lastIndexOf( ';' ); if ( beg != -1 && end != -1 && ( ++beg < end ) ) return command.substring( beg, end ).trim(); else return null; } /** Removes Quotation marks */ static String removeQuotation( String text ) { int beg = text.indexOf( '"' ); int end = text.lastIndexOf( '"' ); if ( beg != -1 && end != -1 && ( ++beg < end ) ) return text.substring( beg, end ); else return null; } /** Let's the collection of features check for it's properties in BeanInfo */ boolean setPropertiesFromBeanInfo( Collection features, Collection code, String name ) { Iterator it = code.iterator(); while( it.hasNext() ) { String statement = (String)it.next(); if ( statement.indexOf( name ) != -1 ) if ( getInitializer( statement ).equals( "null" ) ) // NOI18N return true; else break; } it = features.iterator(); while( it.hasNext() ) { ((BiFeature) it.next()).analyzeCustomization( code ); } return false; } /** Analyze icons properties from bean info */ void setIconsFromBeanInfo ( Collection code ) { Iterator it = code.iterator(); while( it.hasNext() ) { String statement = ( String ) it.next(); if ( statement.indexOf( ICONNAME_C16 ) != -1 ) { iconC16 = removeQuotation( getInitializer( statement ) ); continue; } if ( statement.indexOf( ICONNAME_C32 ) != -1 ) { iconC32 = removeQuotation( getInitializer( statement ) ); continue; } if ( statement.indexOf( ICONNAME_M16 ) != -1 ) { iconM16 = removeQuotation( getInitializer( statement ) ); continue; } if ( statement.indexOf( ICONNAME_M32 ) != -1 ) { iconM32 = removeQuotation( getInitializer( statement ) ); continue; } } } /** Analyze default section */ void setDefaultIdxFromBeanInfo( Collection code ) { Iterator it = code.iterator(); while( it.hasNext() ) { String statement = ( String ) it.next(); if ( statement.indexOf( DEFAULT_PROPERTY_INDEX ) != -1 ) { try { defaultPropertyIndex = Integer.parseInt( getInitializer( statement ) ); } catch ( java.lang.NumberFormatException e ) { defaultPropertyIndex = -1; } continue; } if ( statement.indexOf( DEFAULT_EVENT_INDEX ) != -1 ) { try { defaultEventIndex = Integer.parseInt( getInitializer( statement ) ); } catch ( java.lang.NumberFormatException e ) { defaultEventIndex = -1; } continue; } } } } /* * Log * 11 Gandalf 1.10 1/13/00 Petr Hrebejk i18n mk3 * 10 Gandalf 1.9 1/12/00 Petr Hrebejk i18n * 9 Gandalf 1.8 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 8 Gandalf 1.7 10/11/99 Petr Hrebejk JDK * IndexedPropertyDescriptor bug fix * 7 Gandalf 1.6 8/18/99 Petr Hrebejk BeanInfo analyse moved * to separate thread * 6 Gandalf 1.5 8/9/99 Petr Hrebejk BeanInfo for no * propertes & no events selected * 5 Gandalf 1.4 8/5/99 Petr Hrebejk BeanInfo for Beans with * no Properties or no EventSets fixed * 4 Gandalf 1.3 7/29/99 Petr Hrebejk Patterns in BeanInfo * show correctly only public fields and methods * 3 Gandalf 1.2 7/28/99 Petr Hrebejk Property Mode change fix * 2 Gandalf 1.1 7/26/99 Petr Hrebejk BeanInfo fix & Code * generation fix * 1 Gandalf 1.0 7/26/99 Petr Hrebejk * $ */